Install and Load packages, functions and color palettes

library(readxl)
library(tidyverse)
library(readr)
library(ggplot2)
library(grid)
library(scales)

remove_outliers <- function(x, na.rm = TRUE, ...) {
  qnt <- quantile(x, probs = c(.25, .75), na.rm = na.rm, ...)
  val <- 1.25 * IQR(x, na.rm = na.rm)
  y <- x
  y[x < (qnt[1] - val)] <- NA
  y[x > (qnt[2] + val)] <- NA
  y
}

my_cols <- c( #options for colors 
  "#66C2A5",  
  "#3288BD",  
  "#6A51A3",  
  "#ABDDA4",  
  "#5E4FA2",  
  "#9EBCDA",  
  "#8DD3C7"   
)

my_cols_12 <- c( #options for colors 
  "#ABDDA4",
  "#66C2A5",
  "#8DD3C7",
  "#3288BD",
  "#5DA5DA",
  "#9EBCDA",
  "#6A51A3",
  "#5E4FA2",
  "#8073AC",
  "#B2ABD2",
  "#C7E9B4",
  "#A6DBA0"
)

Set working directory and import data

setwd("...")

data <- read.csv("Assays_calculated.csv") %>%   
  dplyr::select(-c(Signal,Sample_type,Signal_corr)) #remove un-necessary columns

data_clean <- data %>% #remove outliers based on function
  group_by(Assay, Sample_ID, RNA, Assay_comments)%>%
  mutate(Concentration = case_when(
    Sample_ID == "Oocyte" ~ remove_outliers(Concentration),
      TRUE ~ Concentration))%>% 
  ungroup() %>% 
  filter(!is.na(Concentration)) 

Create subsets of data for plots. In this example the columns Assay indicate the different assays performed.

Assay_1 <- filter(data_clean, Assay == "E11-1") 
Assay_2 <- filter(data_clean, Assay == "E11-2")
Assay_3 <- filter(data_clean, Assay == "E11-3")
Assay_4 <- filter(data_clean, Assay == "E11-4")

Assay 1 - Expression time

Assay_1 %>%
  filter(Sample_ID == "Oocyte") %>%
ggplot(aes(x = RNA, y = Concentration, fill = Assay_comments)) +
  geom_boxplot(alpha = 0.5, outlier.shape = NA) +
  geom_point(position=position_jitterdodge(jitter.width = 0.2, dodge.width = 0.8), aes(color = Assay_comments)) +
  theme_classic() +
  theme(
    aspect.ratio = 1,
    axis.title = element_text(size = 14),
  axis.text = element_text(size = 12),
  legend.title = element_text(size = 12),
  legend.text = element_text(size = 11)
  )+
  labs(
    x = "RNA",
    y = "Esculin (µM)",
    title = "",
    fill = "Expression time", color = "Expression time"
  )+
  scale_color_manual(values = c(my_cols))+  scale_fill_manual(values = c(my_cols))

Assay 2 - Time course

Option 1

Assay_2$Assay_comments <- factor( Assay_2$Assay_comments, levels = c( "5 min", "10 min", "15 min", "20 min", "30 min", "45 min", "1 hour" ))

Assay_2 <- Assay_2 %>%mutate(Time = recode(as.character(Assay_comments), "5 min" = "5","10 min" = "10",  "15 min" = "15","20 min" = "20","30 min" = "30","45 min" = "45","1 hour" = "60" ) |> as.numeric())

Assay_2 %>%
  filter(Sample_ID == "Oocyte") %>%
  ggplot(aes(x = Time, y = Concentration, color = RNA, group = RNA)) +
 geom_boxplot(
    aes(fill = RNA, group = interaction(Time, RNA)),width = 3.5,alpha = 0.25, 
    position = position_identity(), outlier.shape = NA) +
  stat_summary(fun = mean, geom = "line", size = 1) +
  geom_point(size = 2, position = position_jitter(width = 0.1)) +
  theme_classic() +
  labs(
    x = "Time (min)",
    y = "Esculin (µM)",
    color = "RNA"
  )+
  scale_color_manual(values = my_cols) + scale_fill_manual(values = my_cols)+
  theme(aspect.ratio = 1.2,
    axis.title = element_text(size = 14),
  axis.text = element_text(size = 12),
  legend.title = element_text(size = 12),
  legend.text = element_text(size = 11)
  )+scale_x_continuous( breaks = c(5, 10, 15, 20, 30, 45, 60),labels = c("5", "10", "15", "20", "30", "45", "60")
  )
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

Option 2

Assay_2 %>%
  filter(Sample_ID == "Oocyte") %>%
ggplot(aes(x = RNA, y = Concentration, fill = Assay_comments)) +
  geom_boxplot(alpha = 0.5, outlier.shape = NA) +
  geom_point(position=position_jitterdodge(jitter.width = 0.2, dodge.width = 0.8), aes(color = Assay_comments)) +
  theme_classic() +
  theme(
    aspect.ratio = 1,
    axis.title = element_text(size = 14),
  axis.text = element_text(size = 12),
  legend.title = element_text(size = 12),
  legend.text = element_text(size = 11)
  )+
  labs(
    x = "RNA",
    y = "Esculin (µM)",
    title = "",
    fill = "Time course", color = "Time course"
  )+  scale_color_manual(values = c(my_cols_12))+  scale_fill_manual(values = c(my_cols_12))

Assay 3 - pH assay

Option 1

Assay_3 <- Assay_3 %>%mutate(pH = recode(as.character(Assay_comments), "pH 4" = 4,"pH 4.5" = 4.5, "pH 5" = 5, "pH 5.5" = 5.5,
  "pH 6" = 6, "pH 6.5" = 6.5, "pH 7.4" = 7.4 ) |> as.factor())

Assay_3 %>%
  filter(Sample_ID == "Oocyte") %>%
ggplot(aes(x = pH, y = Concentration, fill = RNA)) +
  geom_boxplot(alpha = 0.5, outlier.shape = NA) +
  geom_point(position=position_jitterdodge(jitter.width = 0.2, dodge.width = 0.8), aes(color = RNA)) +
  theme_classic() +
  theme(
    aspect.ratio = 1,
    axis.title = element_text(size = 14),
  axis.text = element_text(size = 12),
  legend.title = element_text(size = 12),
  legend.text = element_text(size = 11)
  )+
  labs(
    x = "pH",
    y = "Esculin (µM)",
    title = "",
    fill = "RNA", color = "RNA"
  )+  scale_color_manual(values = c(my_cols))+  scale_fill_manual(values = c(my_cols))

Same plot, but with different colors - in a scale format

library(ggnewscale)

cols_pH <- c(
  "#2F7F6E",  
  "#3E8F7C",
  "#4D9F8A",
  "#5CAF98",
  "#6BBFA6",
  "#7ACFB4",
  "#89DFC2", 
  "#1F5F8A",  
  "#2C6E9B",
  "#397DAC",
  "#468CBD",
  "#53A0CE",
  "#60B4DF",
  "#6DC8F0"    
)

Assay_3 <- Assay_3 %>%
  mutate(RNA_pH = paste0(RNA, "_", Assay_comments))


Assay_3 %>%
  filter(Sample_ID == "Oocyte") %>%
  ggplot(aes(x = pH, y = Concentration)) +
  geom_boxplot(aes(fill = RNA_pH), alpha = 0.5, outlier.shape = NA) +
  geom_point(aes(color = RNA_pH), position = position_jitterdodge(jitter.width = 0.2, dodge.width = 0.8)) +
  scale_fill_manual(values = cols_pH, guide = "none") +
  scale_color_manual(values = cols_pH, guide = "none") +
  new_scale_color() +
  new_scale_fill() +
  geom_point(aes(color = RNA, fill = RNA), alpha = 0, size = 4, show.legend = TRUE) +
    scale_color_manual( name = "RNA", values = c("Mock" = "#5CAF98", "SUC1" ="#468CBD")) +  
  scale_fill_manual( name = "RNA", values = c("Mock" = "#5CAF98", "SUC1" = "#468CBD"),
  guide = guide_legend(override.aes = list(alpha = 1, size = 4) )) +
  theme_classic() +
  labs(
    x = "pH",
    y = "Esculin (µM)"
  )+
  theme(
    aspect.ratio = 1,
    axis.title = element_text(size = 14),
  axis.text = element_text(size = 12),
  legend.title = element_text(size = 12),
  legend.text = element_text(size = 11)
  )

Option 2

Assay_3 %>%
  filter(Sample_ID == "Oocyte") %>%
ggplot(aes(x = RNA, y = Concentration, fill = Assay_comments)) +
  geom_boxplot(alpha = 0.5, outlier.shape = NA) +
  geom_point(position=position_jitterdodge(jitter.width = 0.2, dodge.width = 0.8), aes(color = Assay_comments)) +
  theme_classic() +
  theme(
    aspect.ratio = 1,
    axis.title = element_text(size = 14),
  axis.text = element_text(size = 12),
  legend.title = element_text(size = 12),
  legend.text = element_text(size = 11)
  )+
  labs(
    x = "RNA",
    y = "Esculin (µM)",
    title = "",
    fill = "pH", color = "pH"
  )+  scale_color_manual(values = c(my_cols_12))+  scale_fill_manual(values = c(my_cols_12))

Assay 4 - Competition assay + dose response

Esculin alone = 100 µM esculin in dose response

Assay4_1 <- filter(Assay_4, Assay_comments %in% c("Esculin alone", "Esculin + 2.5 mM sucrose", "Esculin + 2.5 mM glucose"))
Assay4_2<- filter(Assay_4, !Assay_comments %in% c( "Esculin + 2.5 mM sucrose", "Esculin + 2.5 mM glucose"))

Assay4_1$Assay_comments <- factor(Assay4_1$Assay_comments,levels = c( "Esculin alone", "Esculin + 2.5 mM sucrose", "Esculin + 2.5 mM glucose")
)

Assay4_1 %>%
  filter(Sample_ID == "Oocyte") %>%
  ggplot(aes(x = RNA, y = Concentration, fill = Assay_comments)) +
    geom_boxplot(alpha = 0.5, outlier.shape = NA, position = position_dodge(width = 0.8)) +
    geom_point( aes(color = Assay_comments), position = position_jitterdodge(jitter.width = 0.2, dodge.width = 0.8), size = 2  )+
    theme_classic() +
  theme(
    aspect.ratio = 2,
    axis.title = element_text(size = 14),
    axis.text = element_text(size = 12),
    legend.title = element_text(size = 12),
    legend.text = element_text(size = 11)
  ) +
    labs( x = "",y = "Esculin (µM)", fill = "Competition",  color = "Competition")+  scale_color_manual(values = c(my_cols))+  scale_fill_manual(values = c(my_cols))

Assay4_2 <- Assay4_2 %>%
  mutate(Conc = case_when(Assay_comments == "Esculin alone" ~ 100,TRUE ~ as.numeric(gsub(" µM", "", Assay_comments))))
## Warning: There was 1 warning in `mutate()`.
## ℹ In argument: `Conc = case_when(...)`.
## Caused by warning:
## ! NAs introduced by coercion
Assay4_2%>%
  filter(Sample_ID == "Oocyte") %>%
  ggplot(aes(x = Conc, y = Concentration, color = RNA, group = RNA)) +
 geom_boxplot(
    aes(fill = RNA, group = interaction(Conc, RNA)),width = 30,alpha = 0.25, 
    position = position_identity(), outlier.shape = NA) +
  stat_summary(fun = mean, geom = "line", size = 1) +
  geom_point(size = 2, position = position_jitter(width = 0.1)) +
  theme_classic() +
  labs(
    x = "Concentration (µM)",
    y = "Esculin (µM)",
    color = "RNA"
  )+
  scale_color_manual(values = my_cols) + scale_fill_manual(values = my_cols)+
  theme(aspect.ratio = 1.2,
    axis.title = element_text(size = 14),
  axis.text = element_text(size = 12),
  legend.title = element_text(size = 12),
  legend.text = element_text(size = 11)
  )+scale_x_continuous(breaks = c(10, 50, 100, 250, 500))

# R studio Version
rstudioapi::versionInfo()$version
## [1] '2026.7.1.147'
# Session report
sessioninfo::session_info()
## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.5.3 (2026-03-11 ucrt)
##  os       Windows 11 x64 (build 26200)
##  system   x86_64, mingw32
##  ui       RTerm
##  language (EN)
##  collate  Danish_Denmark.utf8
##  ctype    Danish_Denmark.utf8
##  tz       Europe/Copenhagen
##  date     2026-08-25
##  pandoc   3.8.3 @ C:/Program Files/RStudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)
##  quarto   1.9.38 @ C:\\PROGRA~1\\RStudio\\RESOUR~1\\app\\bin\\quarto\\bin\\quarto.exe
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package      * version date (UTC) lib source
##  bslib          0.11.0  2026-05-16 [1] CRAN (R 4.5.3)
##  cachem         1.1.0   2024-05-16 [1] CRAN (R 4.5.3)
##  cellranger     1.1.0   2016-07-27 [1] CRAN (R 4.5.3)
##  cli            3.6.6   2026-04-09 [1] CRAN (R 4.5.3)
##  digest         0.6.39  2025-11-19 [1] CRAN (R 4.5.3)
##  dplyr        * 1.2.1   2026-04-03 [1] CRAN (R 4.5.3)
##  evaluate       1.0.5   2025-08-27 [1] CRAN (R 4.5.3)
##  farver         2.1.2   2024-05-13 [1] CRAN (R 4.5.3)
##  fastmap        1.2.0   2024-05-15 [1] CRAN (R 4.5.3)
##  forcats      * 1.0.1   2025-09-25 [1] CRAN (R 4.5.3)
##  generics       0.1.4   2025-05-09 [1] CRAN (R 4.5.3)
##  ggnewscale   * 0.5.2   2025-06-20 [1] CRAN (R 4.5.3)
##  ggplot2      * 4.0.2   2026-02-03 [1] CRAN (R 4.5.3)
##  glue           1.8.0   2024-09-30 [1] CRAN (R 4.5.3)
##  gtable         0.3.6   2024-10-25 [1] CRAN (R 4.5.3)
##  hms            1.1.4   2025-10-17 [1] CRAN (R 4.5.3)
##  htmltools      0.5.9   2025-12-04 [1] CRAN (R 4.5.3)
##  jquerylib      0.1.4   2021-04-26 [1] CRAN (R 4.5.3)
##  jsonlite       2.0.0   2025-03-27 [1] CRAN (R 4.5.3)
##  knitr          1.51    2025-12-20 [1] CRAN (R 4.5.3)
##  labeling       0.4.3   2023-08-29 [1] CRAN (R 4.5.2)
##  lifecycle      1.0.5   2026-01-08 [1] CRAN (R 4.5.3)
##  lubridate    * 1.9.5   2026-02-04 [1] CRAN (R 4.5.3)
##  magrittr       2.0.5   2026-04-04 [1] CRAN (R 4.5.3)
##  otel           0.2.0   2025-08-29 [1] CRAN (R 4.5.3)
##  pillar         1.11.1  2025-09-17 [1] CRAN (R 4.5.3)
##  pkgconfig      2.0.3   2019-09-22 [1] CRAN (R 4.5.3)
##  purrr        * 1.2.2   2026-04-10 [1] CRAN (R 4.5.3)
##  R6             2.6.1   2025-02-15 [1] CRAN (R 4.5.3)
##  RColorBrewer   1.1-3   2022-04-03 [1] CRAN (R 4.5.2)
##  readr        * 2.2.0   2026-02-19 [1] CRAN (R 4.5.3)
##  readxl       * 1.4.5   2025-03-07 [1] CRAN (R 4.5.3)
##  rlang          1.2.0   2026-04-06 [1] CRAN (R 4.5.3)
##  rmarkdown      2.31    2026-03-26 [1] CRAN (R 4.5.3)
##  rstudioapi     0.19.0  2026-06-11 [1] CRAN (R 4.5.3)
##  S7             0.2.1   2025-11-14 [1] CRAN (R 4.5.3)
##  sass           0.4.10  2025-04-11 [1] CRAN (R 4.5.3)
##  scales       * 1.4.0   2025-04-24 [1] CRAN (R 4.5.3)
##  sessioninfo    1.2.4   2026-06-04 [1] CRAN (R 4.5.3)
##  stringi        1.8.7   2025-03-27 [1] CRAN (R 4.5.2)
##  stringr      * 1.6.0   2025-11-04 [1] CRAN (R 4.5.3)
##  tibble       * 3.3.1   2026-01-11 [1] CRAN (R 4.5.3)
##  tidyr        * 1.3.2   2025-12-19 [1] CRAN (R 4.5.3)
##  tidyselect     1.2.1   2024-03-11 [1] CRAN (R 4.5.3)
##  tidyverse    * 2.0.0   2023-02-22 [1] CRAN (R 4.5.3)
##  timechange     0.4.0   2026-01-29 [1] CRAN (R 4.5.3)
##  tzdb           0.5.0   2025-03-15 [1] CRAN (R 4.5.3)
##  vctrs          0.7.3   2026-04-11 [1] CRAN (R 4.5.3)
##  withr          3.0.3   2026-06-19 [1] CRAN (R 4.5.3)
##  xfun           0.57    2026-03-20 [1] CRAN (R 4.5.3)
##  yaml           2.3.12  2025-12-10 [1] CRAN (R 4.5.3)
## 
##  [1] C:/Users/wck955/AppData/Local/Programs/R/R-4.5.3/library
##  * ── Packages attached to the search path.
## 
## ──────────────────────────────────────────────────────────────────────────────